package com.tjvib.sensor;

import static com.tjvib.Constants.SUCCESS;
import static com.tjvib.view.activity.ZeroLabDeviceActivity.CONFIG_UUID;
import static com.tjvib.view.activity.ZeroLabDeviceActivity.READ_UUID;
import static com.tjvib.view.activity.ZeroLabDeviceActivity.SERVICE_UUID;
import static com.tjvib.view.activity.ZeroLabDeviceActivity.STATUS_UUID;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.content.Context;

import com.tjvib.bean.DataSet;
import com.tjvib.bean.DataSetInfo;
import com.tjvib.ble.OnBleConnectListener;
import com.tjvib.common.Callback;
import com.tjvib.event.ScanStatusEvent;
import com.tjvib.service.ZeroLabSensorService;
import com.tjvib.util.FileUtil;
import com.tjvib.util.LogUtil;
import com.tjvib.util.Manager.UserManager;
import com.tjvib.util.ToastUtil;
import com.tjvib.util.retrofit.BaseResponse;
import com.tjvib.util.retrofit.RetrofitHelper;
import com.tjvib.view.activity.ZeroLabSensorActivity;

import org.greenrobot.eventbus.EventBus;
import org.json.JSONException;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;

import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import okhttp3.MediaType;
import okhttp3.RequestBody;

/**
 * ZeroLab传感器
 */
public class ZeroLabSensor extends Sensor<ZeroLabSensorData> {

    private final int DATA_QUEUE_SIZE = 128;
    private float[] firstTimestamp = {0, 0};
    private static Context context;

    private ZeroLabSensorData currentData = new ZeroLabSensorData();

    private static ArrayList<ZeroLabSensorData> records = new ArrayList<>();
    private static HashMap<String, Integer> add2id = new HashMap<>();

    private static boolean isRecording = false;

    private String mAddress, deviceName = "";

    private int //imuId = 0,
            gyrRange = 0, accRange = 0, magRange = 0, filterMode = 0;
    private boolean accEnable = true, gyrEnable = true, magEnable = true, angularVelEnable = true,
            quaternionEnable = true, eulerAngleEnable = true, linAccEnable = true,
            pressureEnable = true, altitudeEnable = true, temperatureEnable = true;
    private float[] lastTime = {0.0f, 0.0f}, lastAcc = {0.0f, 0.0f};
    private LinkedBlockingDeque<ZeroLabSensorData> dataQueue2 = new LinkedBlockingDeque<>(1000);

    private BluetoothDevice device;
    private LinkedBlockingQueue<byte[]> rawDataQueue = new LinkedBlockingQueue<>();
    private LinkedBlockingQueue<Compdata> decodeDataQueue = new LinkedBlockingQueue<>();
    private Thread recordThread, decodeThread;
    private volatile boolean isRunning = true;

    private class Compdata{
        byte[] data;
        String add;
    }

    private ZeroLabSensor() {
    }

    public ZeroLabSensor(String name, String mAddress, Context context) {
        this.deviceName = name;
        this.mAddress = mAddress;
        this.context = context;

        currentData = new ZeroLabSensorData();
        records = new ArrayList<>();

        startRecordThread();
        startDecodeThread();
    }

    public BluetoothDevice getDevice() {
        return device;
    }

    public void setDevice(BluetoothDevice device) {
        this.device = device;
    }

    @Override
    public boolean connect() {
        if (connectionStatus != SENSOR_STATUS_DISCONNECTED) {
            return false;
        }

        if(ZeroLabSensorService.bleManager != null){
//            String sendMsg = "aad50700003fff3f40008012";
            ZeroLabSensorService.bleManager.connectBleDevice(context,
                    device, 3000,
                    SERVICE_UUID, READ_UUID, CONFIG_UUID, STATUS_UUID,
                    onBleConnectListener);
            connectionStatus = SENSOR_STATUS_CONNECTED;
            ZeroLabSensorService.bleManager.setOnBleConnectListener(onBleConnectListener);

            if(ZeroLabSensorActivity.fir == 0)
                ZeroLabSensorActivity.fir = System.currentTimeMillis();
//            ZeroLabSensorService.bleManager.sendMessage(sendMsg);
        }
        return true;
    }


    // 启动记录线程
    private void startRecordThread() {
        recordThread = new Thread(() -> {
            while (isRunning) {
                try {
                    byte[] data = rawDataQueue.take();
                    // 记录原始数据到文件
                    FileUtil.writeRawData(context, data);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    LogUtil.e("记录线程被中断");
                }
            }
        });
        recordThread.start();
    }

    // 启动解码线程
    private void startDecodeThread() {
        decodeThread = new Thread(() -> {
            while (isRunning) {
                try {
                    Compdata compdata = decodeDataQueue.take();
                    decodeAndStoreData(compdata.data, compdata.add);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    LogUtil.e("解码线程被中断");
                }
            }
        });
        decodeThread.start();
    }

    private void decodeAndStoreData(byte[] data, String add) {
        int package_index = 0;
        // 帧头 0xAA
        if (data[0] != (byte) 0xAA) {
            return; // 帧头错误
        }

        // 解码IMU数据上报
        if (data[1] == (byte) 0x10) {
            byte[] payload = new byte[data.length - 8 - 1]; // 减去帧头 指令 数据长度 子指令 MT_ID 流水号 校验码长度
            System.arraycopy(data, 8, payload, 0, payload.length); // 从索引7开始复制，跳过帧头 指令 数据长度 子指令 MT_ID 流水号 校验码

            currentData.localtime = System.currentTimeMillis();
            float temp = ByteBuffer.wrap(payload, package_index, 4).order(ByteOrder.LITTLE_ENDIAN).getFloat() / 1000f;
            package_index += 4;

            for (int i = 0; i < 4; i++) {
                currentData.quat[i] = ByteBuffer.wrap(payload, 4 * i + package_index, 4)
                        .order(ByteOrder.LITTLE_ENDIAN).getFloat();
            }
            package_index += 16;

            for (int i = 0; i < 3; i++) {
                currentData.euler[i] = ByteBuffer.wrap(payload, package_index + 4 * i, 4)
                        .order(ByteOrder.LITTLE_ENDIAN).getFloat();
            }
            package_index += 12;

            for (int i = 0; i < 3; i++) {
                currentData.acc[i] = ByteBuffer.wrap(payload, package_index + 4 * i, 4)
                        .order(ByteOrder.LITTLE_ENDIAN).getFloat();
            }
            package_index += 12;

            int id = add2id.get(add);//, otherid = id == 1 ? 2 : 1;
//            if(add2id.size() > 1) {
//                if (lastAcc[id - 1] != 0 &&
//                        (Math.abs(lastAcc[id - 1] / Math.abs(currentData.acc[0]) - 1) >
//                                Math.abs(lastAcc[otherid - 1] / Math.abs(currentData.acc[0]) - 1)))
//                    id = otherid;
//            }
//            lastAcc[id-1] = Math.abs(currentData.acc[0]);
            currentData.imuId = id;
            if (!isRecording && currentData.timestamp == 0.0f) {
                currentData.timestamp = 0.0f;
            } else {
                if (firstTimestamp[id - 1] == 0) firstTimestamp[id - 1] = temp;
                lastTime[id - 1] = Math.abs(temp - firstTimestamp[id - 1] - lastTime[id - 1]) > 0.011f ?
                        lastTime[id - 1] + 0.01f : temp - firstTimestamp[id - 1];
                currentData.timestamp = lastTime[id - 1];
            }
//            LogUtil.i("add=" + add + " id=" + id
//                    + " timestamp=" + currentData.timestamp
//                    + " fir=" + firstTimestamp[id - 1] + " last=" + lastTime[id - 1]
//                    + " time=" + ByteBuffer.wrap(payload, package_index, 4)
//                    .order(ByteOrder.LITTLE_ENDIAN).getFloat());


            for (int i = 0; i < 3; i++) {
                currentData.gyr[i] = ByteBuffer.wrap(payload, package_index + 4 * i, 4)
                        .order(ByteOrder.LITTLE_ENDIAN).getFloat();
            }
            package_index += 12;

            for (int i = 0; i < 3; i++) {
                currentData.mag[i] = ByteBuffer.wrap(payload, package_index + 4 * i, 4)
                        .order(ByteOrder.LITTLE_ENDIAN).getFloat();
            }
            package_index += 12;

            for (int i = 0; i < 3; i++) {
                currentData.linAcc[i] = ByteBuffer.wrap(payload, package_index + 4 * i, 4)
                        .order(ByteOrder.LITTLE_ENDIAN).getFloat();
            }
            package_index += 12;

            currentData.temperature = ByteBuffer.wrap(payload, package_index, 4).order(ByteOrder.LITTLE_ENDIAN).getFloat();

            // 同步数据队列和记录逻辑
            if(id == 1){
                synchronized (dataQueue) {
                    if (dataQueue.size() >= DATA_QUEUE_SIZE)
                        dataQueue.removeLast();
                    dataQueue.addFirst(new ZeroLabSensorData(currentData));

                    if (isRecording && tmpFileWriter != null) {
                        records.add(new ZeroLabSensorData(currentData));
                        try {
                            tmpFileWriter.append(String.valueOf(currentData.imuId)).append(",")
                                    .append(String.valueOf(currentData.localtime)).append(",")
                                    .append(String.valueOf(currentData.timestamp)).append(",")
                                    .append(String.valueOf(currentData.frameNumber)).append(",")
                                    .append(String.valueOf(currentData.acc[0])).append(",")
                                    .append(String.valueOf(currentData.acc[1])).append(",")
                                    .append(String.valueOf(currentData.acc[2])).append(",")
                                    .append(String.valueOf(currentData.gyr[0])).append(",")
                                    .append(String.valueOf(currentData.gyr[1])).append(",")
                                    .append(String.valueOf(currentData.gyr[2])).append(",")
                                    .append(String.valueOf(currentData.mag[0])).append(",")
                                    .append(String.valueOf(currentData.mag[1])).append(",")
                                    .append(String.valueOf(currentData.mag[2])).append(",")
                                    .append(String.valueOf(currentData.euler[0])).append(",")
                                    .append(String.valueOf(currentData.euler[1])).append(",")
                                    .append(String.valueOf(currentData.euler[2])).append(",")
                                    .append(String.valueOf(currentData.quat[0])).append(",")
                                    .append(String.valueOf(currentData.quat[1])).append(",")
                                    .append(String.valueOf(currentData.quat[2])).append(",")
                                    .append(String.valueOf(currentData.quat[3])).append(",")
                                    .append(String.valueOf(currentData.linAcc[0])).append(",")
                                    .append(String.valueOf(currentData.linAcc[1])).append(",")
                                    .append(String.valueOf(currentData.linAcc[2])).append(",")
                                    .append(String.valueOf(currentData.pressure)).append(",")
                                    .append(String.valueOf(currentData.altitude)).append(",")
                                    .append(String.valueOf(currentData.temperature)).append(",")
                                    .append(String.valueOf(currentData.batteryLevel)).append("\n");
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            } else{
                synchronized (dataQueue2) {
                    if (dataQueue2.size() >= DATA_QUEUE_SIZE)
                        dataQueue2.removeLast();
                    dataQueue2.addFirst(new ZeroLabSensorData(currentData));

                    if (isRecording && tmpFileWriter != null) {
                        records.add(new ZeroLabSensorData(currentData));
                        try {
                            tmpFileWriter.append(String.valueOf(currentData.imuId)).append(",")
                                    .append(String.valueOf(currentData.localtime)).append(",")
                                    .append(String.valueOf(currentData.timestamp)).append(",")
                                    .append(String.valueOf(currentData.frameNumber)).append(",")
                                    .append(String.valueOf(currentData.acc[0])).append(",")
                                    .append(String.valueOf(currentData.acc[1])).append(",")
                                    .append(String.valueOf(currentData.acc[2])).append(",")
                                    .append(String.valueOf(currentData.gyr[0])).append(",")
                                    .append(String.valueOf(currentData.gyr[1])).append(",")
                                    .append(String.valueOf(currentData.gyr[2])).append(",")
                                    .append(String.valueOf(currentData.mag[0])).append(",")
                                    .append(String.valueOf(currentData.mag[1])).append(",")
                                    .append(String.valueOf(currentData.mag[2])).append(",")
                                    .append(String.valueOf(currentData.euler[0])).append(",")
                                    .append(String.valueOf(currentData.euler[1])).append(",")
                                    .append(String.valueOf(currentData.euler[2])).append(",")
                                    .append(String.valueOf(currentData.quat[0])).append(",")
                                    .append(String.valueOf(currentData.quat[1])).append(",")
                                    .append(String.valueOf(currentData.quat[2])).append(",")
                                    .append(String.valueOf(currentData.quat[3])).append(",")
                                    .append(String.valueOf(currentData.linAcc[0])).append(",")
                                    .append(String.valueOf(currentData.linAcc[1])).append(",")
                                    .append(String.valueOf(currentData.linAcc[2])).append(",")
                                    .append(String.valueOf(currentData.pressure)).append(",")
                                    .append(String.valueOf(currentData.altitude)).append(",")
                                    .append(String.valueOf(currentData.temperature)).append(",")
                                    .append(String.valueOf(currentData.batteryLevel)).append("\n");
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    /**
     * ZLBUSDataDecoder - decodeRecvIMUDataStr(data)
     * @param data
     */
    public void onSensorChanged(byte[] data, String add) {
        if (isRunning) {
            try {
                rawDataQueue.put(data);
                Compdata compdata = new Compdata();
                compdata.data = data;
                compdata.add = add;
                decodeDataQueue.put(compdata);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                LogUtil.e("添加数据到队列时被中断");
            }
        }

//
//        int package_index = 0;
//        // 帧头 0xAA
//        if (data[0] != (byte) 0xAA) {
//            return; // 帧头错误
//        }
//
//        // 解码IMU数据上报
//        if (data[1] == (byte) 0x10) {
//            byte[] payload = new byte[data.length - 8 - 1]; // 减去帧头 指令 数据长度 子指令 MT_ID 流水号 校验码长度
//            System.arraycopy(data, 8, payload, 0, payload.length); // 从索引7开始复制，跳过帧头 指令 数据长度 子指令 MT_ID 流水号 校验码
//
//            currentData.imuId = id;
//            currentData.localtime = System.currentTimeMillis();
//            if(!isRecording && currentData.timestamp == 0.0f){
//                currentData.timestamp = 0.0f;
//            } else {
//                float temp = ByteBuffer.wrap(payload, package_index, 4).order(ByteOrder.LITTLE_ENDIAN).getFloat() / 1000f;
//                if (firstTimestamp[id - 1] == 0) firstTimestamp[id - 1] = temp;
//                lastTime[id - 1] = Math.abs(temp - firstTimestamp[id - 1] - lastTime[id - 1]) > 0.011f ?
//                        lastTime[id - 1] + 0.01f : temp - firstTimestamp[id - 1];
//                currentData.timestamp = lastTime[id - 1];
//            }
//            LogUtil.i("add="+add+" id="+id
//                    +" timestamp="+currentData.timestamp
//                    +" fir="+firstTimestamp[id-1]+" last="+lastTime[id-1]
//                    +" time="+ByteBuffer.wrap(payload, package_index, 4)
//                    .order(ByteOrder.LITTLE_ENDIAN).getFloat());
//            package_index += 4;
//            for (int i = 0; i < 4; i++) {
//                currentData.quat[i] = ByteBuffer.wrap(payload, 4 * i + package_index, 4)
//                        .order(ByteOrder.LITTLE_ENDIAN).getFloat();
//            }
//            package_index += 16;
//
//            for (int i = 0; i < 3; i++) {
//                currentData.euler[i] = ByteBuffer.wrap(payload, package_index + 4 * i, 4)
//                        .order(ByteOrder.LITTLE_ENDIAN).getFloat();
//            }
//            package_index += 12;
//
//            for (int i = 0; i < 3; i++) {
//                currentData.acc[i] = ByteBuffer.wrap(payload, package_index + 4 * i, 4)
//                        .order(ByteOrder.LITTLE_ENDIAN).getFloat();
//            }
//            package_index += 12;
//
//            for (int i = 0; i < 3; i++) {
//                currentData.gyr[i] = ByteBuffer.wrap(payload, package_index + 4 * i, 4)
//                        .order(ByteOrder.LITTLE_ENDIAN).getFloat();
//            }
//            package_index += 12;
//
//            for (int i = 0; i < 3; i++) {
//                currentData.mag[i] = ByteBuffer.wrap(payload, package_index + 4 * i, 4)
//                        .order(ByteOrder.LITTLE_ENDIAN).getFloat();
//            }
//            package_index += 12;
//
//            for (int i = 0; i < 3; i++) {
//                currentData.linAcc[i] = ByteBuffer.wrap(payload, package_index + 4 * i, 4)
//                        .order(ByteOrder.LITTLE_ENDIAN).getFloat();
//            }
//            package_index += 12;
//
//            currentData.temperature = ByteBuffer.wrap(payload, package_index, 4).order(ByteOrder.LITTLE_ENDIAN).getFloat();
//
//            if(id == 1){
//                synchronized (dataQueue) {
//                    if (dataQueue.size() >= DATA_QUEUE_SIZE)
//                        dataQueue.removeLast();
//                    dataQueue.addFirst(new ZeroLabSensorData(currentData));
//
//                    if (isRecording && tmpFileWriter != null) {
//                        records.add(new ZeroLabSensorData(currentData));
//                        try {
//                            tmpFileWriter.append(String.valueOf(currentData.imuId)).append(",")
//                                    .append(String.valueOf(currentData.localtime)).append(",")
//                                    .append(String.valueOf(currentData.timestamp)).append(",")
//                                    .append(String.valueOf(currentData.frameNumber)).append(",")
//                                    .append(String.valueOf(currentData.acc[0])).append(",")
//                                    .append(String.valueOf(currentData.acc[1])).append(",")
//                                    .append(String.valueOf(currentData.acc[2])).append(",")
//                                    .append(String.valueOf(currentData.gyr[0])).append(",")
//                                    .append(String.valueOf(currentData.gyr[1])).append(",")
//                                    .append(String.valueOf(currentData.gyr[2])).append(",")
//                                    .append(String.valueOf(currentData.mag[0])).append(",")
//                                    .append(String.valueOf(currentData.mag[1])).append(",")
//                                    .append(String.valueOf(currentData.mag[2])).append(",")
//                                    .append(String.valueOf(currentData.euler[0])).append(",")
//                                    .append(String.valueOf(currentData.euler[1])).append(",")
//                                    .append(String.valueOf(currentData.euler[2])).append(",")
//                                    .append(String.valueOf(currentData.quat[0])).append(",")
//                                    .append(String.valueOf(currentData.quat[1])).append(",")
//                                    .append(String.valueOf(currentData.quat[2])).append(",")
//                                    .append(String.valueOf(currentData.quat[3])).append(",")
//                                    .append(String.valueOf(currentData.linAcc[0])).append(",")
//                                    .append(String.valueOf(currentData.linAcc[1])).append(",")
//                                    .append(String.valueOf(currentData.linAcc[2])).append(",")
//                                    .append(String.valueOf(currentData.pressure)).append(",")
//                                    .append(String.valueOf(currentData.altitude)).append(",")
//                                    .append(String.valueOf(currentData.temperature)).append(",")
//                                    .append(String.valueOf(currentData.batteryLevel)).append("\n");
//                        } catch (IOException e) {
//                            e.printStackTrace();
//                        }
//                    }
//                }
//            } else{
//                synchronized (dataQueue2) {
//                    if (dataQueue2.size() >= DATA_QUEUE_SIZE)
//                        dataQueue2.removeLast();
//                    dataQueue2.addFirst(new ZeroLabSensorData(currentData));
//
//                    if (isRecording && tmpFileWriter != null) {
//                        records.add(new ZeroLabSensorData(currentData));
//                        try {
//                            tmpFileWriter.append(String.valueOf(currentData.imuId)).append(",")
//                                    .append(String.valueOf(currentData.localtime)).append(",")
//                                    .append(String.valueOf(currentData.timestamp)).append(",")
//                                    .append(String.valueOf(currentData.frameNumber)).append(",")
//                                    .append(String.valueOf(currentData.acc[0])).append(",")
//                                    .append(String.valueOf(currentData.acc[1])).append(",")
//                                    .append(String.valueOf(currentData.acc[2])).append(",")
//                                    .append(String.valueOf(currentData.gyr[0])).append(",")
//                                    .append(String.valueOf(currentData.gyr[1])).append(",")
//                                    .append(String.valueOf(currentData.gyr[2])).append(",")
//                                    .append(String.valueOf(currentData.mag[0])).append(",")
//                                    .append(String.valueOf(currentData.mag[1])).append(",")
//                                    .append(String.valueOf(currentData.mag[2])).append(",")
//                                    .append(String.valueOf(currentData.euler[0])).append(",")
//                                    .append(String.valueOf(currentData.euler[1])).append(",")
//                                    .append(String.valueOf(currentData.euler[2])).append(",")
//                                    .append(String.valueOf(currentData.quat[0])).append(",")
//                                    .append(String.valueOf(currentData.quat[1])).append(",")
//                                    .append(String.valueOf(currentData.quat[2])).append(",")
//                                    .append(String.valueOf(currentData.quat[3])).append(",")
//                                    .append(String.valueOf(currentData.linAcc[0])).append(",")
//                                    .append(String.valueOf(currentData.linAcc[1])).append(",")
//                                    .append(String.valueOf(currentData.linAcc[2])).append(",")
//                                    .append(String.valueOf(currentData.pressure)).append(",")
//                                    .append(String.valueOf(currentData.altitude)).append(",")
//                                    .append(String.valueOf(currentData.temperature)).append(",")
//                                    .append(String.valueOf(currentData.batteryLevel)).append("\n");
//                        } catch (IOException e) {
//                            e.printStackTrace();
//                        }
//                    }
//                }
//            }
//        }
    }


    @Override
    public void disconnect() {
        if(ZeroLabSensorService.bleManager != null){
            ZeroLabSensorService.bleManager.disConnectDevice();
            add2id.clear();
            firstTimestamp = new float[]{0.0f, 0.0f};
            lastTime = new float[]{0.0f, 0.0f};
        }
        connectionStatus = SENSOR_STATUS_DISCONNECTED;

        isRunning = false;
        if (recordThread != null) recordThread.interrupt();
        if (decodeThread != null) decodeThread.interrupt();
    }

    @Override
    public void setStreamFrequency(int freq) {
        streamingFrequency = freq;
    }

    @Override
    public void resetTimestamp() {
        firstTimestamp = new float[]{0, 0};
        if(ZeroLabSensorActivity.firstTimestamp[0] == 0)
            ZeroLabSensorActivity.firstTimestamp[0] = firstTimestamp[0];
        if(ZeroLabSensorActivity.firstTimestamp[1] == 0)
            ZeroLabSensorActivity.firstTimestamp[1] = firstTimestamp[1];
    }

    @Override
    public ZeroLabSensorData getData() {
        if (connectionStatus != SENSOR_STATUS_CONNECTED) return null;
        ZeroLabSensorData data = null;
//        synchronized (dataQueue) {
//            while (dataQueue.size() > 0) {
//                data = dataQueue.getLast();
//                dataQueue.removeLast();
//            }
//        }
        synchronized (dataQueue) {
            if (dataQueue.size() > 0) {
                data = dataQueue.getLast();
                dataQueue.removeLast();
            }
        }
        return data;
    }

    public ZeroLabSensorData getData2() {
        if (connectionStatus != SENSOR_STATUS_CONNECTED) return null;
        ZeroLabSensorData data = null;
        synchronized (dataQueue2) {
            if (dataQueue2.size() > 0) {
                data = dataQueue2.getLast();
                dataQueue2.removeLast();
            }
        }
        return data;
    }

    public static void startRecording(Context context) {
        ZeroLabSensor.context = context;
        isRecording = true;
        tmpFileWriter = FileUtil.getDataSetTempFileWriter(context);
        try {
            if (tmpFileWriter != null) {
                tmpFileWriter.append("sensor\n");
            }
//            LogUtil.w("tmpFileWriter="+tmpFileWriter);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public static void stopRecording() {
        isRecording = false;
        try {
            if (tmpFileWriter != null) {
                tmpFileWriter.close();
                tmpFileWriter = null;
            }
//            LogUtil.w("tmpFileWriter="+tmpFileWriter);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public static boolean isRecording() {
        return isRecording;
    }


    public static void discardData() {
        records.clear();
    }


    public static void storeData(String name, Callback callback) {
        DataSetInfo info = new DataSetInfo(-1, name, "lpmsb2", false,
                new Timestamp(System.currentTimeMillis()).toString());
        DataSet<ZeroLabSensorData> dataSet = new DataSet<>(info, records);
        new Thread(() -> {
            String dataSetStr = null;
            try {
                dataSetStr = dataSet.toJsonString();
            } catch (JSONException e) {
                e.printStackTrace();
            }
            RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), dataSetStr);
            RetrofitHelper.getInstance().create()
                    .collectLpmsB2("" + UserManager.getInstance().getUserId(), requestBody)
                    .subscribe(new Observer<BaseResponse>() {
                        @Override
                        public void onSubscribe(Disposable d) {
                            LogUtil.e("onSubscribe "+d);
                        }

                        @Override
                        public void onNext(BaseResponse value) {
                            if (value.getCode() == SUCCESS) {
                                callback.onSuccess(value.getMessage(), null);
                                FileUtil.deleteDataSetTempFile(context);
                            } else {
                                callback.onFail(value.getMessage(), null);
                            }
                            LogUtil.i("collectSensor "+value.getCode() + " " + value.getMessage() + " " + value.getData());
                        }

                        @Override
                        public void onError(Throwable e) {
                            if (e != null) {
                                ToastUtil.show(e.getMessage());
                                LogUtil.e("e=" + e.getMessage());
                            } else {
                                LogUtil.e("null");
                            }
                            callback.onError(""+e.getMessage(), ""+e);
                        }

                        @Override
                        public void onComplete() {
                            LogUtil.e("onComplete");
                        }
                    });
        }).start();
    }

    public void setImuId(int id){
        if (connectionStatus != SENSOR_STATUS_CONNECTED) return;
//        this.imuId = id;
    }
    public String getDeviceName() {
        return deviceName;
    }
    public String getAddress() {
        return mAddress;
    }
    public int getImuId(String add) {
        if(add2id.containsKey(add))
            return add2id.get(add);
        else
            return -1;
    }
    public int getGyroRange() {
        return gyrRange;
    }
    public int getAccRange() {
        return accRange;
    }
    public int getFilterMode() {
        return filterMode;
    }
    public int getMagRange() {
        return magRange;
    }
    public boolean isGyroDataEnabled() {
        return gyrEnable;
    }
    public boolean isAccDataEnabled() {
        return accEnable;
    }
    public boolean isMagDataEnabled() {
        return magEnable;
    }
    public boolean isAngularVelDataEnable() {
        return angularVelEnable;
    }
    public boolean isQuaternionDataEnabled() {
        return quaternionEnable;
    }
    public boolean isEulerDataEnabled() {
        return eulerAngleEnable;
    }
    public boolean isLinAccDataEnabled() {
        return linAccEnable;
    }
    public boolean isPressureDataEnabled() {
        return pressureEnable;
    }
    public boolean isAltitudeDataEnabled() {
        return altitudeEnable;
    }
    public boolean isTemperatureDataEnabled() {
        return temperatureEnable;
    }


    /**
     * 连接回调
     */
    public OnBleConnectListener onBleConnectListener = new OnBleConnectListener() {
        @Override
        public void onConnecting(BluetoothGatt bluetoothGatt, BluetoothDevice bluetoothDevice) {
            LogUtil.e("onConnecting");
            connectionStatus = SENSOR_STATUS_CONNECTING;
        }

        @Override
        public void onConnectSuccess(BluetoothGatt bluetoothGatt, BluetoothDevice bluetoothDevice, int status) {
            //因为服务发现成功之后，才能通讯，所以在成功发现服务的地方表示连接成功
            LogUtil.i("onConnectSuccess");
            if(add2id.size() == 0)
                add2id.put(bluetoothDevice.getAddress(), 1);
            else if(!add2id.containsKey(bluetoothDevice.getAddress()) && add2id.size() == 1) {
                Iterator<Map.Entry<String, Integer>> entries = add2id.entrySet().iterator();
                while (entries.hasNext()) {
                    Map.Entry<String, Integer> entry = entries.next();
                    if(entry.getValue() == 1)
                        add2id.put(bluetoothDevice.getAddress(), 2);
                    else
                        add2id.put(bluetoothDevice.getAddress(), 1);
                }
            }

            LogUtil.e("add2id "+bluetoothDevice.getAddress() +" - "+ add2id.get(bluetoothDevice.getAddress()));
            connectionStatus = SENSOR_STATUS_CONNECTED;
        }

        @Override
        public void onConnectFailure(BluetoothGatt bluetoothGatt, BluetoothDevice bluetoothDevice, String exception, int status) {
            LogUtil.d("onConnectFailure");
            connectionStatus = SENSOR_STATUS_DISCONNECTED;
            EventBus.getDefault().post(new ScanStatusEvent("CONNECT_FAILURE"));
        }

        @Override
        public void onDisConnecting(BluetoothGatt bluetoothGatt, BluetoothDevice bluetoothDevice) {
            LogUtil.e("onDisConnecting");
        }

        @Override
        public void onDisConnectSuccess(BluetoothGatt bluetoothGatt, BluetoothDevice bluetoothDevice, int status) {
            LogUtil.d("DISCONNECT_SUCCESS");
            connectionStatus = SENSOR_STATUS_DISCONNECTED;
            add2id.remove(bluetoothDevice.getAddress());
            ScanStatusEvent scanStatusEvent = new ScanStatusEvent("DISCONNECT_SUCCESS");
            scanStatusEvent.setState(status);
            EventBus.getDefault().post(scanStatusEvent);
        }

        @Override
        public void onServiceDiscoverySucceed(BluetoothGatt bluetoothGatt, BluetoothDevice bluetoothDevice, int status) {
            //因为服务发现成功之后，才能通讯，所以在成功发现服务的地方表示连接成功
            LogUtil.d("onServiceDiscoverySucceed");
            connectionStatus = SENSOR_STATUS_CONNECTED;
            EventBus.getDefault().post(new ScanStatusEvent("CONNECT_SUCCESS"));
        }

        @Override
        public void onServiceDiscoveryFailed(BluetoothGatt bluetoothGatt, BluetoothDevice bluetoothDevice, String failMsg) {
            LogUtil.d("onServiceDiscoveryFailed");
            connectionStatus = SENSOR_STATUS_DISCONNECTED;
            EventBus.getDefault().post(new ScanStatusEvent("CONNECT_FAILURE"));
        }

        @Override
        public void onReceiveMessage(BluetoothGatt bluetoothGatt, BluetoothDevice bluetoothDevice,
                                     BluetoothGattCharacteristic characteristic, byte[] msg) {
//            LogUtil.i("RECEIVE_SUCCESS");
            ScanStatusEvent scanStatusEvent = new ScanStatusEvent("RECEIVE_SUCCESS");
            scanStatusEvent.setData(msg);
            if(add2id.containsKey(bluetoothDevice.getAddress())) {
                mAddress = bluetoothDevice.getAddress();
//                onSensorChanged(msg, add2id.get(bluetoothDevice.getAddress()), bluetoothDevice.getAddress());
                onSensorChanged(msg, bluetoothDevice.getAddress());
            }
            EventBus.getDefault().post(scanStatusEvent);
        }

        @Override
        public void onReceiveError(String errorMsg) {
            LogUtil.e("RECEIVE_FAILURE");
            ScanStatusEvent scanStatusEvent = new ScanStatusEvent("RECEIVE_FAILURE");
            scanStatusEvent.setMsg(errorMsg);
            EventBus.getDefault().post(scanStatusEvent);
        }

        @Override
        public void onWriteSuccess(BluetoothGatt bluetoothGatt, BluetoothDevice bluetoothDevice, byte[] msg) {
            LogUtil.e("SEND_SUCCESS");
            ScanStatusEvent scanStatusEvent = new ScanStatusEvent("SEND_SUCCESS");
            scanStatusEvent.setData(msg);
            EventBus.getDefault().post(scanStatusEvent);
        }

        @Override
        public void onWriteFailure(BluetoothGatt bluetoothGatt, BluetoothDevice bluetoothDevice,
                                   byte[] msg, String errorMsg) {
            LogUtil.e("onWriteFailure");
            ScanStatusEvent scanStatusEvent = new ScanStatusEvent("SEND_FAILURE");
            scanStatusEvent.setData(msg);
            EventBus.getDefault().post(scanStatusEvent);
        }

        @Override
        public void onReadRssi(BluetoothGatt bluetoothGatt, int Rssi, int status) {
            LogUtil.e("onReadRssi");
        }

        @Override
        public void onMTUSetSuccess(String successMTU, int newMtu) {
            LogUtil.e("onMTUSetSuccess");
        }

        @Override
        public void onMTUSetFailure(String failMTU) {
            LogUtil.e("onMTUSetFailure");
        }
    };
}
